import threading
import time
import inspect
from typing import Callable, Type, Dict, Any, List
from simplehtf.core.phase import PhaseDescriptor, PhaseResult, PhaseRecord

class TestExecutor:
    def __init__(self, test, always_continue = True):
        self.always_continue = always_continue
        self.test = test
        
    
    def run(self, phases):
        result = True
        for phase in phases:
            phase_record = PhaseRecord().set_phase_name(phase.name)
            self.test.test_record.append_phase_record(phase_record)
            try:
                phase_record.mark_phase_start()
                outcome = phase(self.test)
                
            except Exception as e:
                phase_record.mark_phase_finish('FAIL')
                result = False
                outcome = 'ERROR'

            if outcome == PhaseResult.CONTINUE or outcome == None:
                phase_record.mark_phase_finish('PASS')
            else:
                #TODO 处理其他outcome情况
                phase_record.mark_phase_finish('FAIL')
                result = False
            if self.always_continue:
                continue
            
        return result


class TestRecord:
    def __init__(self,metadata):
        self.metadata = metadata
        self.phase_records = []
        self.start_time = None
        self.end_time = None
        self.outcome = None

    def append_phase_record(self,phase_record:PhaseRecord):
        self.phase_records.append(phase_record)

    def mark_test_start(self):
        self.start_time = time.time()

    def mark_test_finish(self,outcome):
        self.end_time = time.time()
        self.outcome = outcome

    def to_dict(self):
        phase_records_dict = []
        for i in self.phase_records:
            phase_records_dict.append(i.to_dict())
        return {
            'metadata':self.metadata,
            'start_time':self.start_time,
            'end_time':self.end_time,
            'outcome':self.outcome,
            'phase_records':phase_records_dict
        }

class Test:
    def __init__(self,*raw_nodes,**metadata):
        if metadata.get('name'):
            self.name = metadata.get('name')
        else :
            self.name = 'simplehtf_test'

        self.raw_nodes = raw_nodes

        self.phases: List[PhaseDescriptor] = []

        self.output = None

        self.test_record = TestRecord(metadata)

        self.metadata: Dict[str, Any] = metadata

    def set_output(self,output):
        self.output = output
    
    def build_phases(self,):
        for i in self.raw_nodes:
            phase = PhaseDescriptor(i)
            if self.phases:
                self.phases.append(phase)
            else:
                self.phases = []
                self.phases.append(phase)

        return self

    def execute(self, start_func:Callable = None):
        self.test_record.mark_test_start()
        if start_func != None:
            uid = start_func()

        executor = TestExecutor(self)

        test_outcome = executor.run(self.phases)
        self.test_record.mark_test_finish(test_outcome)

        return test_outcome
